package com.rc.common.util;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.concurrent.ListenableFutureCallback;

import java.util.UUID;

/**
 * RabbitMQ工具类
 * 提供RabbitMQ消息发送的便捷方法
 */
@RequiredArgsConstructor
@Slf4j
public class RabbitMqHelper {
    // RabbitTemplate实例
    private final RabbitTemplate rabbitTemplate;

    /**
     * 发送普通消息
     * @param exchange 交换机名称
     * @param routingKey 路由键
     * @param msg 消息内容
     */
    public void sendMessage(String exchange, String routingKey, Object msg){
        log.debug("准备发送消息，exchange:{}, routingKey:{}, msg:{}", exchange, routingKey, msg);
        rabbitTemplate.convertAndSend(exchange, routingKey, msg);
    }

    /**
     * 发送延迟消息
     * @param exchange 交换机名称
     * @param routingKey 路由键
     * @param msg 消息内容
     * @param delay 延迟时间（毫秒）
     */
    public void sendDelayMessage(String exchange, String routingKey, Object msg, int delay){
        rabbitTemplate.convertAndSend(exchange, routingKey, msg, message -> {
            // 设置消息延迟时间
            message.getMessageProperties().setDelay(delay);
            return message;
        });
    }

    /**
     * 发送带确认机制的消息
     * @param exchange 交换机名称
     * @param routingKey 路由键
     * @param msg 消息内容
     * @param maxRetries 最大重试次数
     */
    public void sendMessageWithConfirm(String exchange, String routingKey, Object msg, int maxRetries){
        log.debug("准备发送消息，exchange:{}, routingKey:{}, msg:{}", exchange, routingKey, msg);
        // 创建关联数据
        CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
        // 添加回调监听器
        cd.getFuture().addCallback(new ListenableFutureCallback<>() {
            int retryCount; // 重试计数器

            @Override
            public void onFailure(Throwable ex) {
                log.error("处理ack回执失败", ex);
            }

            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                if (result != null && !result.isAck()) {
                    log.debug("消息发送失败，收到nack，已重试次数：{}", retryCount);
                    // 检查重试次数
                    if(retryCount >= maxRetries){
                        log.error("消息发送重试次数耗尽，发送失败");
                        return;
                    }
                    // 创建新的关联数据
                    CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
                    cd.getFuture().addCallback(this);
                    // 重试发送消息
                    rabbitTemplate.convertAndSend(exchange, routingKey, msg, cd);
                    retryCount++;
                }
            }
        });
        // 首次发送消息
        rabbitTemplate.convertAndSend(exchange, routingKey, msg, cd);
    }
}
